package cn.pku.eecs.ldn.view.gallery;

import java.util.Observable;

import android.util.Log;

public class ImageViewState extends Observable {
	private static final String TAG = "ImageViewState";
	private static final boolean DEBUG = true;

	float maxZoom;
	float minZoom;
	float currentZoom;
	float initialZoom;
	float secondaryZoom;

	float panX;
	float panY;

	boolean isImageReady = false;

	int bmpWidth, bmpHeight;
	int viewWidth, viewHeight;
	float focusX = -1f, focusY = -1f;

	public ImageViewState(int bmpWidth, int bmpHeight, int viewWidth,
			int viewHeight) {
		init(bmpWidth, bmpHeight, viewWidth, viewHeight);
		isImageReady = true;
	}

	private void init(int bmpWidth, int bmpHeight, int viewWidth, int viewHeight) {
		this.bmpWidth = bmpWidth;
		this.bmpHeight = bmpHeight;
		this.viewWidth = viewWidth;
		this.viewHeight = viewHeight;
		setFocus(viewWidth / 2, viewHeight / 2);
		initZoom();
		initPosition();
	}

	private void initZoom() {
		float ratioBmp = bmpWidth * 1f / bmpHeight;
		float ratioView = viewWidth * 1f / viewHeight;
		if (ratioBmp > ratioView) {
			initialZoom = viewWidth * 1f / bmpWidth;
			secondaryZoom = viewHeight * 1f / bmpHeight;
		} else {
			initialZoom = viewHeight * 1f / bmpHeight;
			secondaryZoom = viewWidth * 1f / bmpWidth;
		}
		currentZoom = initialZoom;
		minZoom = Math.min(initialZoom, 1f);
		maxZoom = Math.max(secondaryZoom, 2f);
	}

	private void initPosition() {
		panX = panY = 0.5f;
	}

	public void setFocus(float x, float y) {
		focusX = x;
		focusY = y;
	}

	public void pan(float dxInPixels, float dyInPixels) {
		panX = panX - dxInPixels / (bmpWidth * currentZoom);
		if (notLarger(currentZoom, secondaryZoom)) {
			// do NOT pan vertically
			if (DEBUG)
				Log.d(TAG, "pan(): no need to pan vertically");
		} else {
			panY = panX - dyInPixels / (bmpHeight * currentZoom);
		}
	}

	public void zoom(float ratio) {
		zoomWithFocus(ratio);
	}

	private void zoomWithFocus(float ratio) {
		float dxInPixels = viewWidth / 2 - focusX;
		float dyInPixels = viewHeight / 2 - focusY;
		pan(dxInPixels, dyInPixels);
		currentZoom *= ratio;
		pan(-dxInPixels, -dyInPixels);
	}
	
	public void updateDisplay() {
		setChanged();
		notifyObservers();
	}

	private boolean notLarger(float f1, float f2) {
		if (f1 < f2) {
			return true;
		}
		if (equal(f1, f2)) {
			return true;
		}
		return false;
	}

	private boolean equal(float f1, float f2) {
		if (Math.abs(f1 - f2) < 0.0001) {
			return true;
		}
		return false;
	}
}
